package com.jingdianjichi.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.jingdianjichi.api.subject.entity.*;
import com.jingdianjichi.api.subject.entity.dto.PracticeSubjectDTO;
import com.jingdianjichi.subject.common.enums.IsDeletedFlagEnum;
import com.jingdianjichi.subject.common.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.subject.domain.comvert.SubjectCategoryConverter;
import com.jingdianjichi.subject.domain.comvert.SubjectLabelConverter;
import com.jingdianjichi.subject.domain.entity.SubjectCategoryBO;
import com.jingdianjichi.subject.domain.entity.SubjectLabelBO;
import com.jingdianjichi.subject.domain.service.SubjectCategoryDomainService;
import com.jingdianjichi.subject.domain.util.CacheUtil;
import com.jingdianjichi.subject.infra.basic.entity.SubjectCategory;
import com.jingdianjichi.subject.infra.basic.entity.SubjectLabel;
import com.jingdianjichi.subject.infra.basic.entity.SubjectMapping;
import com.jingdianjichi.subject.infra.basic.service.SubjectCategoryService;
import com.jingdianjichi.subject.infra.basic.service.SubjectLabelService;
import com.jingdianjichi.subject.infra.basic.service.SubjectMappingService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {

    @Resource
    private SubjectCategoryService subjectCategoryService;
    @Resource
    private SubjectMappingService subjectMappingService;
    @Resource
    private SubjectLabelService subjectLabelService;

    @Resource
    private ThreadPoolExecutor labelTreadPool;

    @Resource
    private CacheUtil cacheUtil;

    /**
     * 新增大类分类
     *
     * @param subjectCategoryBO
     */
    public void add(SubjectCategoryBO subjectCategoryBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.add.bo:{}", JSON.toJSONString(subjectCategoryBO));

        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE
                .convertBoToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        subjectCategoryService.insert(subjectCategory);
    }

    /**
     * 查询岗位大类
     *
     * @param subjectCategoryBO
     * @return
     */
    public List<SubjectCategoryBO> queryCategory(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE
                .convertBoToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);

        List<SubjectCategoryBO> subjectCategoryBOList = SubjectCategoryConverter.INSTANCE
                .convertSubjectCategoryListToSubjectCategoryBOList(subjectCategoryList);

        //给岗位添加题目数量
        for (SubjectCategoryBO categoryBO : subjectCategoryBOList) {
            Integer count = subjectCategoryService.querySubjectCount(categoryBO.getId());
            categoryBO.setCount(count);
        }

        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryDomainServiceImpl.queryCategory.subjectCategoryBOList:{}", JSON.toJSONString(subjectCategoryBOList));
        }
        return subjectCategoryBOList;
    }

    /**
     * 更新大类分类
     *
     * @param subjectCategoryBO
     * @return
     */
    public Boolean update(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE
                .convertBoToCategory(subjectCategoryBO);
        int count = subjectCategoryService.update(subjectCategory);
        return count > 0;
    }

    /**
     * 删除大类分类
     *
     * @param subjectCategoryBO
     * @return
     */
    public Boolean delete(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE
                .convertBoToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        int count = subjectCategoryService.update(subjectCategory);
        return count > 0;
    }

    @Override
    @SneakyThrows
    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
        String cacheKey = "categoryAndLabel." + subjectCategoryBO.getId();
        List<SubjectCategoryBO> subjectCategoryBOS = cacheUtil.getResult(cacheKey,
                SubjectCategoryBO.class, (key) -> getSubjectCategoryBOS(subjectCategoryBO.getId()));
        return subjectCategoryBOS;
    }

    @Override
    public List<SpecialPracticeVO> getSpecialPracticeContent() {
        List<SpecialPracticeVO> specialPracticeVOList = new LinkedList<>();
        //专项练习过滤出，得到分类父id，以及类型题目数量

        List<Integer> subjectTypeList = new LinkedList<>();
        subjectTypeList.add(SubjectInfoTypeEnum.RADIO.getCode());
        subjectTypeList.add(SubjectInfoTypeEnum.MULTIPLE.getCode());
        subjectTypeList.add(SubjectInfoTypeEnum.JUDGE.getCode());

        //以题目类型查询父id，以及题目数量
        Category category = new Category();
        category.setSubjectTypeList(subjectTypeList);
        List<Category> categoryList = subjectCategoryService.getPrimaryCategory(category);

        if (CollectionUtils.isEmpty(categoryList)) {
            return specialPracticeVOList;
        }
        categoryList.forEach(info -> {
            SpecialPracticeVO specialPracticeVO = new SpecialPracticeVO();
            //设置大类id
            specialPracticeVO.setPrimaryCategoryId(info.getParentId());
            //查询大类信息
            Category result = subjectCategoryService.selectById(info.getParentId());
            //设置大类名称
            specialPracticeVO.setPrimaryCategoryName(result.getCategoryName());

            //查询二级分类信息
            Category parameter = new Category();
            parameter.setCategoryType(2);
            parameter.setParentId(info.getParentId());
            List<Category> categories = subjectCategoryService.selectList(parameter);
            if (CollectionUtils.isEmpty(categories)) {
                return;
            }


            List<SpecialPracticeCategoryVO> categoryVOS = new LinkedList();
            //遍历二级分类，封装信息
            categories.forEach(secondaryCategory -> {
                //
                List<SpecialPracticeLabelVO> labelVOList = getLabelVOList(secondaryCategory.getId(), subjectTypeList);
                if (CollectionUtils.isEmpty(labelVOList)) {
                    return;
                }
                //封装二级分类信息
                SpecialPracticeCategoryVO specialPracticeCategoryVO = new SpecialPracticeCategoryVO();
                //二级分类id,名称
                specialPracticeCategoryVO.setCategoryId(secondaryCategory.getId());
                specialPracticeCategoryVO.setCategoryName(secondaryCategory.getCategoryName());
                //封装标签信息
                List<SpecialPracticeLabelVO> labelList = new LinkedList<>();
                labelVOList.forEach(labelVo -> {
                    SpecialPracticeLabelVO specialPracticeLabelVO = new SpecialPracticeLabelVO();
                    specialPracticeLabelVO.setId(labelVo.getId());
                    specialPracticeLabelVO.setAssembleId(labelVo.getAssembleId());
                    specialPracticeLabelVO.setLabelName(labelVo.getLabelName());
                    //构建二级分类的标签集合
                    labelList.add(specialPracticeLabelVO);
                });
                //装进二级分类标签集合中
                specialPracticeCategoryVO.setLabelList(labelList);
                //构建一级分类中的二级分类集合
                categoryVOS.add(specialPracticeCategoryVO);
            });
            //装进一级分类的二级分类集合中
            specialPracticeVO.setCategoryList(categoryVOS);
            specialPracticeVOList.add(specialPracticeVO);
        });
        return specialPracticeVOList;
    }

    /**
     * 构建套卷名称,大类id
     */
    @Override
    public Map<String, Object> getPracticeName(PracticeSubjectDTO practiceSubjectDTO) {

        List<String> assembleIds = practiceSubjectDTO.getAssembleIds();
        Set<Long> categoryIdSet = new HashSet<>();
        assembleIds.forEach(assembleId ->
        {
            Long categoryId = Long.valueOf(assembleId.split("-")[0]);
            categoryIdSet.add(categoryId);
        });
        StringBuffer practiceName = new StringBuffer();
        int i = 1;
        for (Long categoryId : categoryIdSet) {
            if (i > 2) {
                break;
            }
            Category category = subjectCategoryService.selectById(categoryId);
            practiceName.append(category.getCategoryName());
            practiceName.append("、");
            i = i + 1;
        }
        practiceName.deleteCharAt(practiceName.length() - 1);
        if (i == 2) {
            practiceName.append("专项练习");
        } else {
            practiceName.append("等专项练习");
        }

        String labelId = assembleIds.get(0).split("-")[1];
        SubjectLabel subjectLabel = subjectLabelService.queryById(Long.valueOf(labelId));

        Map<String, Object> map = new HashMap<>();
        map.put("practiceName",practiceName.toString());
        map.put("categoryId",subjectLabel.getCategoryId());

        return map;
    }

    private List<SpecialPracticeLabelVO> getLabelVOList(Long id, List<Integer> subjectTypeList) {
        List<LabelCount> countList = subjectMappingService.getLabelSubjectCount(id, subjectTypeList);
        if (CollectionUtils.isEmpty(countList)) {
            return Collections.emptyList();
        }
        List<SpecialPracticeLabelVO> voList = new LinkedList<>();
        countList.forEach(count -> {
            SpecialPracticeLabelVO vo = new SpecialPracticeLabelVO();
            vo.setId(count.getLabelId());
            vo.setAssembleId(id + "-" + count.getLabelId());
            SubjectLabel subjectLabel = subjectLabelService.queryById(count.getLabelId());
            vo.setLabelName(subjectLabel.getLabelName());
            voList.add(vo);
        });
        return voList;
    }


    private List<SubjectCategoryBO> getSubjectCategoryBOS(Long categoryId) {
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(categoryId);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        //通过父id,查询出所有二级分类
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);

        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryCategoryAndLabel.subjectCategoryList:{}",
                    JSON.toJSONString(subjectCategoryList));
        }
        List<SubjectCategoryBO> categoryBOList = SubjectCategoryConverter.INSTANCE.convertSubjectCategoryListToSubjectCategoryBOList(subjectCategoryList);

        Map<Long, List<SubjectLabelBO>> map = new HashMap<>();
        List<CompletableFuture<Map<Long, List<SubjectLabelBO>>>> futureList = categoryBOList.stream().map(categoryBO -> CompletableFuture.supplyAsync(() -> getLabelBOList(categoryBO), labelTreadPool)).collect(Collectors.toList());
        for (CompletableFuture<Map<Long, List<SubjectLabelBO>>> mapCompletableFuture : futureList) {
            try {
                Map<Long, List<SubjectLabelBO>> resultMap = mapCompletableFuture.get();
                if (!CollectionUtils.isEmpty(resultMap)) {
                    map.putAll(resultMap);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        /*通过二级分类id查询出二级分类所对应的标签
        List<FutureTask<Map<Long,List<SubjectLabelBO>>>>  futureTasksList=new LinkedList<>();
        //线程池并发调用
        for (SubjectCategoryBO categoryBO : categoryBOList) {
            Map<Long, List<SubjectLabelBO>> result = getLabelBOList(categoryBO);
            if(CollectionUtils.isEmpty(result)){
                continue;
            }
            FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask = new FutureTask<>(() -> result);
            futureTasksList.add(futureTask);
            labelTreadPool.submit(futureTask);
        }
        for (FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask : futureTasksList) {
            Map<Long,List<SubjectLabelBO>> resultMap = futureTask.get();
            if(CollectionUtils.isEmpty(resultMap)){
                continue;
            }
            map.putAll(resultMap);
        }*/

        for (SubjectCategoryBO categoryBO : categoryBOList) {
            categoryBO.setLabelBOList(map.get(categoryBO.getId()));
        }
        return categoryBOList;
    }

    //一个分类id,对应多个标签信息
    private Map<Long, List<SubjectLabelBO>> getLabelBOList(SubjectCategoryBO categoryBO) {
        if (log.isInfoEnabled()) {
            log.info("getLabelBOList:{}", JSON.toJSONString(categoryBO));
        }
        Map<Long, List<SubjectLabelBO>> labelMap = new HashMap<>();
        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setCategoryId(categoryBO.getId());
        //查询出所有该二级分类所对应的labelId
        List<SubjectMapping> mappingList = subjectMappingService.queryLabelId(subjectMapping);

        if (CollectionUtils.isEmpty(mappingList)) {
            return null;
        }
        //使用stream流取出所有的labelId
        List<Long> labelIdList = mappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
        //拿所有的labelId去查询label表中标签信息
        List<SubjectLabel> subjectLabelList = subjectLabelService.batchQueryById(labelIdList);
        //把label标签信息封装到List<SubjectLabelBO>
        List<SubjectLabelBO> labelBoList = new LinkedList<>();
        for (SubjectLabel subjectLabel : subjectLabelList) {
            labelBoList.add(SubjectLabelConverter.INSTANCE.convertLabelToBO(subjectLabel));
        }
        labelMap.put(categoryBO.getId(), labelBoList);
        return labelMap;
    }
}
